
import * as AsyncLock from "async-lock";
import * as fs from "fs";
import * as path from "path";
import * as vscode from "vscode";
import { WebviewPanel } from "vscode";
import * as utils from "../utils";
import localize from "../localize";
const lock = new AsyncLock();

export class ViewOption {
  public iconPath?: string;
  public path!: string;
  public title!: string;
  public splitView: boolean = false;
  /**
   * keep single page by viewType
   */
  public singlePage?: boolean;
  /**
   * kill exists panel
   */
  public killHidden?: boolean;
  /**
   * receive webview send message
   */
  public receiveListener?: (viewPanel: WebviewPanel, message: any) => void;
  /**
   * callback when init success.
   */
  public initListener?: (viewPanel: WebviewPanel) => void;
  public extensionUri?: vscode.Uri;
  public listener?: (webView: vscode.WebviewView, message: any) => void;
}

interface ViewState {
  instance: WebviewPanel;
  creating: boolean;
  initListener: (viewPanel: WebviewPanel) => void;
  // 监听
  receiveListener: (viewPanel: WebviewPanel, message: any) => void;
}

export class ViewManager {
  private static viewStatu: { [key: string]: ViewState | null } = {};
  private static webviewPath: string;
  private static extensionPath: string;
  public static initExtesnsionPath(extensionPath: string) {
    this.webviewPath = path.join(extensionPath, "dist");
    this.extensionPath = extensionPath;
  }

  public static createWebviewPanel(
    viewOption: ViewOption
  ): Promise<WebviewPanel> {
    return new Promise((resolve, reject) => {
      lock.acquire("viewManager", (done) => {
        if (typeof viewOption.singlePage === "undefined") {
          viewOption.singlePage = true;
        }
        if (typeof viewOption.killHidden === "undefined") {
          viewOption.killHidden = true;
        }

        if (!viewOption.singlePage) {
          viewOption.title = viewOption.title + new Date().getTime();
        }

        const currentStatus = this.viewStatu[viewOption.title];
        if (viewOption.singlePage && currentStatus) {
          if (
            viewOption.killHidden &&
            currentStatus.instance.visible === false
          ) {
            currentStatus.instance.dispose();
          } else {
            done();
            if (currentStatus.creating && viewOption.initListener) {
              currentStatus.initListener = viewOption.initListener;
            } else if (viewOption.initListener) {
              viewOption.initListener(currentStatus.instance);
            }
            if (viewOption.receiveListener) {
              currentStatus.receiveListener = viewOption.receiveListener;
            }
            return Promise.resolve(currentStatus.instance);
          }
        }
        const targetPath = `${this.webviewPath}/${viewOption.path}.html`;
        console.log("targetPath : " + targetPath);
        fs.readFile(targetPath, "utf8", async (err, data) => {
          if (err) {
            reject(err);
            return;
          }
          const webviewPanel = vscode.window.createWebviewPanel(
            viewOption.title,
            viewOption.title,
            {
              viewColumn: viewOption.splitView
                ? vscode.ViewColumn.Two
                : vscode.ViewColumn.One,
              preserveFocus: true,
            },
            { enableScripts: true, retainContextWhenHidden: true }
          );

          if (viewOption.iconPath) {
            webviewPanel.iconPath = vscode.Uri.file(
              `${this.webviewPath}/${viewOption.iconPath}`
            );
          }
          const parentPath = path.resolve(targetPath, "..");
          webviewPanel.webview.html = utils.buildInclude(
            this.webviewPath,
            utils.buildPath(data, webviewPanel.webview, parentPath),
            parentPath
          );

          this.viewStatu[viewOption.title] = {
            creating: true,
            instance: webviewPanel,
            initListener: viewOption.initListener!,
            // 监听
            receiveListener: viewOption.receiveListener!,
          };
          webviewPanel.onDidDispose(() => {
            this.viewStatu[viewOption.title] = null;
          });
          const newStatus = this.viewStatu[viewOption.title];
          webviewPanel.webview.onDidReceiveMessage((message) => {
            if (message.type === "init" && newStatus) {
              newStatus.creating = false;
              if (newStatus.initListener) {
                newStatus.initListener(webviewPanel);
              }

              const language = vscode.env.language;
              webviewPanel.webview.postMessage({
                type: "LANGUAGE",
                value: language,
              });
            } else if (newStatus && newStatus.receiveListener) {
              newStatus.receiveListener(webviewPanel, message);
            }
          });
          resolve(webviewPanel);
          done();
        });
      });
    });
  }
  public static createWebviewViewProvider(
    viewOption: ViewOption
  ): any {

      let provider: SidebarViewProvider | undefined = undefined;

      // const targetPath = `${this.webviewPath}/${viewOption.path}.html`;
      const targetPath = path.join(this.extensionPath, "media", "operation.html");
      console.log("targetPath : " + targetPath);

      if(viewOption.extensionUri){
        provider = new SidebarViewProvider(
          // this.webviewPath,
          targetPath,
          viewOption.extensionUri
          // , viewOption
          // , data
        )
      }
      return provider;
  }

//   public static async createWebviewViewProviderAsync(
//     viewOption: ViewOption
//   ): Promise<any> {

//     return new Promise((resolve, reject) => {
//         let provider: SidebarViewProvider | undefined = undefined;

//         // const targetPath = `${this.webviewPath}/${viewOption.path}.html`;
//         const targetPath = path.join(this.extensionPath, "media", "operation.html");
//         console.log("targetPath : " + targetPath);
//         fs.readFile(targetPath, "utf8", (err, data) => {
//           if (err) {
//             reject(err);
//             return;
//           }
//           if (viewOption?.extensionUri != undefined) {
//             provider = new SidebarViewProvider(
//               // this.webviewPath,
//               targetPath,
//               viewOption.extensionUri
//               // , viewOption
//               // , data
//             )
//             resolve(provider);
//           }
//         });
//       });
//       return;
//   }
}

export class SidebarViewProvider implements vscode.WebviewViewProvider {

  public static readonly viewType = 'project.operationView';

  private _view?: vscode.WebviewView;

  constructor(
    // private webviewPath: string,
    private targetPath: string,
    private readonly _extensionUri: vscode.Uri,
    // private readonly viewOption: ViewOption,
    // private html: string,
  ) { }

  public resolveWebviewView(
    webviewView: vscode.WebviewView,
    context: vscode.WebviewViewResolveContext,
    _token: vscode.CancellationToken,
  ) {
    this._view = webviewView;

    webviewView.webview.options = {
      // Allow scripts in the webview
      enableScripts: true,

      localResourceRoots: [
        this._extensionUri,
        vscode.Uri.joinPath(this._extensionUri, 'media'),
      ]
    };

    webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);

    webviewView.webview.onDidReceiveMessage(data => {
      switch (data.type) {
        case 'init':
          this.sendInit();
          break;
        case 'build':
          vscode.commands.executeCommand("workbench.action.tasks.build");
          break;
        case 'run':
          vscode.commands.executeCommand("workbench.action.tasks.runTask");
          break;
        case 'debug':
          vscode.commands.executeCommand("debug.openView");
          break;

        case 'package':
          vscode.commands.executeCommand("project.buildPackage")
          break;

        case 'create':
          vscode.commands.executeCommand("project.createProject");
          break;

        case 'config':
          vscode.commands.executeCommand("project.configProject")
          break;
      }
    });
  }

  public status(code: string) {
    if (this._view) {
      this._view.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders
      this._view.webview.postMessage({ type: 'status', code: code });
    }
  }


  public sendInit(){
    
    const operations = [
      {type:'create', title: localize("language.createNewProject"), status: 1},
      // {type:'config', title: localize("language.configTheProject"), status: 1},
      {type:'build', title: localize("language.buildProject"), status: 1},
      {type:'debug', title: localize("language.debugProject"), status: 1},
      {type:'run', title: localize("language.runProject"), status: 1},
      // {type:'package', title: localize("language.BuildPackage"), status: 1}
  ];
    if (this._view) {
      this._view.webview.postMessage({ type: 'init', list: operations });
    }
  }

  private _getHtmlForWebview(webview: vscode.Webview) {
    // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview.
    const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'operation.js'));
    // Do the same for the stylesheet.
    const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css'));
    const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css'));
    const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'operation.css'));

    let html = fs.readFileSync(this.targetPath, "utf-8");
    // Use a nonce to only allow a specific script to be run.
    const nonce = utils.getNonce();
    // html = html.replace(/\$\{scriptUri\}/g, scriptUri.toString);
    html = html.replace(/\$\$webview.cspSource\$\$/g, webview.cspSource);
    html = html.replace(/\$\$styleResetUri\$\$/g, styleResetUri.toString());
    html = html.replace(/\$\$styleVSCodeUri\$\$/g, styleVSCodeUri.toString());
    html = html.replace(/\$\$styleMainUri\$\$/g, styleMainUri.toString());
    html = html.replace(/\$\$scriptUri\$\$/g, scriptUri.toString());
    html = html.replace(/\$\$nonce\$\$/g, nonce);
    
    
    return html;
  }
}
